package com.xxl.job.admin.controller;

import com.xxl.job.admin.core.cron.CronExpression;
import com.xxl.job.admin.core.exception.XxlJobException;
import com.xxl.job.admin.core.model.*;
import com.xxl.job.admin.core.route.ExecutorRouteStrategyEnum;
import com.xxl.job.admin.core.scheduler.MisfireStrategyEnum;
import com.xxl.job.admin.core.scheduler.ScheduleTypeEnum;
import com.xxl.job.admin.core.thread.JobScheduleHelper;
import com.xxl.job.admin.core.thread.JobTriggerPoolHelper;
import com.xxl.job.admin.core.trigger.TriggerTypeEnum;
import com.xxl.job.admin.core.util.I18nUtil;
import com.xxl.job.admin.dao.XxlJobGroupDao;
import com.xxl.job.admin.dao.XxlJobInfoDao;
import com.xxl.job.admin.dao.XxlJobLogDao;
import com.xxl.job.admin.service.LoginService;
import com.xxl.job.admin.service.XxlJobService;
import com.xxl.job.core.biz.model.ReturnT;
import com.xxl.job.core.enums.ExecutorBlockStrategyEnum;
import com.xxl.job.core.glue.GlueTypeEnum;
import com.xxl.job.core.util.DateUtil;
import freemarker.template.utility.StringUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.text.ParseException;
import java.util.*;

/**
 * index controller
 * @author xuxueli 2015-12-19 16:13:16
 */
@Controller
@RequestMapping("/jobinfo")
public class JobInfoController {
	private static Logger logger = LoggerFactory.getLogger(JobInfoController.class);

	@Resource
	private XxlJobGroupDao xxlJobGroupDao;

	@Resource
	private XxlJobLogDao xxlJobLogDao;

	@Resource
	private XxlJobInfoDao xxlJobInfoDao;
	@Resource
	private XxlJobService xxlJobService;
	
	@RequestMapping
	public String index(HttpServletRequest request, Model model, @RequestParam(required = false, defaultValue = "-1") int jobGroup) {

		// 枚举-字典
		model.addAttribute("ExecutorRouteStrategyEnum", ExecutorRouteStrategyEnum.values());	    // 路由策略-列表
		model.addAttribute("GlueTypeEnum", GlueTypeEnum.values());								// Glue类型-字典
		model.addAttribute("ExecutorBlockStrategyEnum", ExecutorBlockStrategyEnum.values());	    // 阻塞处理策略-字典
		model.addAttribute("ScheduleTypeEnum", ScheduleTypeEnum.values());	    				// 调度类型
		model.addAttribute("MisfireStrategyEnum", MisfireStrategyEnum.values());	    			// 调度过期策略

		// 执行器列表
		List<XxlJobGroup> jobGroupList_all =  xxlJobGroupDao.findAll();

		// filter group
		List<XxlJobGroup> jobGroupList = filterJobGroupByRole(request, jobGroupList_all);
		if (jobGroupList==null || jobGroupList.size()==0) {
			throw new XxlJobException(I18nUtil.getString("jobgroup_empty"));
		}

		model.addAttribute("JobGroupList", jobGroupList);
		model.addAttribute("jobGroup", jobGroup);

		return "jobinfo/jobinfo.index";
	}

	public static List<XxlJobGroup> filterJobGroupByRole(HttpServletRequest request, List<XxlJobGroup> jobGroupList_all){
		List<XxlJobGroup> jobGroupList = new ArrayList<>();
		if (jobGroupList_all!=null && jobGroupList_all.size()>0) {
			XxlJobUser loginUser = (XxlJobUser) request.getAttribute(LoginService.LOGIN_IDENTITY_KEY);
			if (loginUser.getRole() == 1) {
				jobGroupList = jobGroupList_all;
			} else {
				List<String> groupIdStrs = new ArrayList<>();
				if (loginUser.getPermission()!=null && loginUser.getPermission().trim().length()>0) {
					groupIdStrs = Arrays.asList(loginUser.getPermission().trim().split(","));
				}
				for (XxlJobGroup groupItem:jobGroupList_all) {
					if (groupIdStrs.contains(String.valueOf(groupItem.getId()))) {
						jobGroupList.add(groupItem);
					}
				}
			}
		}
		return jobGroupList;
	}
	public static void validPermission(HttpServletRequest request, int jobGroup) {
		XxlJobUser loginUser = (XxlJobUser) request.getAttribute(LoginService.LOGIN_IDENTITY_KEY);
		if (!loginUser.validPermission(jobGroup)) {
			throw new RuntimeException(I18nUtil.getString("system_permission_limit") + "[username="+ loginUser.getUsername() +"]");
		}
	}
	
	@RequestMapping("/pageList")
	@ResponseBody
	public Map<String, Object> pageList(@RequestParam(required = false, defaultValue = "0") int start,  
			@RequestParam(required = false, defaultValue = "10") int length,
			int jobGroup, int triggerStatus, String jobDesc, String executorHandler, String author) {
		
		return xxlJobService.pageList(start, length, jobGroup, triggerStatus, jobDesc, executorHandler, author);
	}
	
	@RequestMapping("/add")
	@ResponseBody
	public ReturnT<String> add(XxlJobInfo jobInfo) {
		return xxlJobService.add(jobInfo);
	}
	
	@RequestMapping("/update")
	@ResponseBody
	public ReturnT<String> update(XxlJobInfo jobInfo) {
		return xxlJobService.update(jobInfo);
	}
	
	@RequestMapping("/remove")
	@ResponseBody
	public ReturnT<String> remove(int id) {
		return xxlJobService.remove(id);
	}
	
	@RequestMapping("/stop")
	@ResponseBody
	public ReturnT<String> pause(int id) {
		return xxlJobService.stop(id);
	}
	
	@RequestMapping("/start")
	@ResponseBody
	public ReturnT<String> start(int id) {
		return xxlJobService.start(id);
	}
	
	@RequestMapping("/trigger")
	@ResponseBody
	//@PermissionLimit(limit = false)
	public ReturnT<String> triggerJob(int id, String executorParam, String addressList) {
		// force cover job param
		if (executorParam == null) {
			executorParam = "";
		}

		JobTriggerPoolHelper.trigger(id, TriggerTypeEnum.MANUAL, -1, null, executorParam, addressList);
		return ReturnT.SUCCESS;
	}

	@RequestMapping("/triggershell")
	@ResponseBody
	//@PermissionLimit(limit = false)
	public ReturnT<String> triggershell(@RequestBody ExecuteShellDetailTableLog executeShellDetailTableLog, String executorParam, String addressList) {
		// force cover job param
		XxlJobLog xxlJobLog = null;
		try {
			if (executorParam == null) {
				executorParam = "";
			}
			logger.info("sjcx调用shell开始");
			String excName = executeShellDetailTableLog.getExcName();
			XxlJobGroup xxlJobGroup = xxlJobGroupDao.findByName(excName);
			XxlJobInfo xxlJobInfo = new XxlJobInfo();
			xxlJobInfo.setJobGroup(xxlJobGroup.getId());
			xxlJobInfo.setJobDesc(executeShellDetailTableLog.getId());
			xxlJobInfo.setAuthor(executeShellDetailTableLog.getUsrid());
			xxlJobInfo.setAlarmEmail("");
			xxlJobInfo.setScheduleType("NONE");
			xxlJobInfo.setScheduleConf("");
			xxlJobInfo.setMisfireStrategy("DO_NOTHING");
			xxlJobInfo.setExecutorRouteStrategy("FIRST");
			xxlJobInfo.setExecutorHandler("");
			xxlJobInfo.setExecutorParam("");
			xxlJobInfo.setExecutorBlockStrategy("SERIAL_EXECUTION");
			xxlJobInfo.setExecutorTimeout(0);
			xxlJobInfo.setExecutorFailRetryCount(0);
			xxlJobInfo.setGlueType("GLUE_SHELL");
			xxlJobInfo.setGlueRemark("GLUE代码初始化");
			xxlJobInfo.setChildJobId("");
			xxlJobInfo.setTriggerLastTime(0);
			xxlJobInfo.setTriggerNextTime(0);
			xxlJobInfo.setTriggerStatus(0);
			if ("0".equals(executeShellDetailTableLog.getCompmthd())) {
				executeShellDetailTableLog.setCompmthd("");
			}
			//imp_main_diqp.sh ${JOBID} ${FILESEP} ${USRID}~${FILENAME}~${FILESUFX}~${TABSCHEMA}~${TABNAME}~${CHARSET}~${HASHEADER}~${MAXERRNO}~${ISCOMP}~${COMPMTHD}
			String shellR = "sh " + executeShellDetailTableLog.getShellName() + " " + executeShellDetailTableLog.getId() + " " +
					"\"" + executeShellDetailTableLog.getFilesep() + "\"" + " "
					+ executeShellDetailTableLog.getUsrid() + "~"
					+ executeShellDetailTableLog.getFilename() + "~"
					+ executeShellDetailTableLog.getFilesufx() + "~"
					+ executeShellDetailTableLog.getTabschema() + "~"
					+ executeShellDetailTableLog.getTabname() + "~"
					+ executeShellDetailTableLog.getCharset() + "~"
					+ executeShellDetailTableLog.getHasheader() + "~"
					+ executeShellDetailTableLog.getMaxerrno() + "~"
					+ executeShellDetailTableLog.getIscomp() + "~"
					+ executeShellDetailTableLog.getCompmthd();
			xxlJobInfo.setGlueSource(shellR);
			xxlJobService.add(xxlJobInfo);
			XxlJobInfo byJobDesc = xxlJobInfoDao.findByJobDesc(xxlJobInfo.getJobDesc());
			logger.info("sjcx调用脚本jobid=" + byJobDesc.getId());
			JobTriggerPoolHelper.trigger(byJobDesc.getId(), TriggerTypeEnum.MANUAL, -1, null, executorParam, addressList);
//			xxlJobLog = xxlJobLogDao.findByJobId(byJobDesc.getId());
//			xxlJobService.remove(byJobDesc.getId());
//
//			logger.info("sjcx调用脚本返回logid=" + xxlJobLog.getId());
			return  new ReturnT<String>(Integer.toString(byJobDesc.getId()));
		} catch (NumberFormatException e) {
			logger.error("sjcx调用shell报错", e);
			return ReturnT.FAIL;
		}

	}

	@RequestMapping("/triggerLinMon")
	@ResponseBody
	//@PermissionLimit(limit = false)
	public ReturnT<String> triggerLinMon(@RequestBody LinMon linMon,String executorParam, String addressList) {
		// force cover job param
		XxlJobLog xxlJobLog = null;
		try {
			if (executorParam == null) {
				executorParam = "";
			}
			logger.info("sjcxlinux监控调用shell开始");
			String excName = linMon.getShellHandle();
			XxlJobGroup xxlJobGroup = xxlJobGroupDao.findByName(excName);
			XxlJobInfo xxlJobInfo = new XxlJobInfo();
			xxlJobInfo.setJobGroup(xxlJobGroup.getId());
			xxlJobInfo.setJobDesc(linMon.getWeiyixxlId());
			xxlJobInfo.setAuthor(linMon.getCreUser());
			xxlJobInfo.setAlarmEmail("");
			xxlJobInfo.setScheduleType("NONE");
			xxlJobInfo.setScheduleConf("");
			xxlJobInfo.setMisfireStrategy("DO_NOTHING");
			xxlJobInfo.setExecutorRouteStrategy("FIRST");
			xxlJobInfo.setExecutorHandler("");
			xxlJobInfo.setExecutorParam("");
			xxlJobInfo.setExecutorBlockStrategy("SERIAL_EXECUTION");
			xxlJobInfo.setExecutorTimeout(0);
			xxlJobInfo.setExecutorFailRetryCount(0);
			xxlJobInfo.setGlueType("GLUE_SHELL");
			xxlJobInfo.setGlueRemark("GLUE代码初始化");
			xxlJobInfo.setChildJobId("");
			xxlJobInfo.setTriggerLastTime(0);
			xxlJobInfo.setTriggerNextTime(0);
			xxlJobInfo.setTriggerStatus(0);
			//imp_main_diqp.sh ${JOBID} ${FILESEP} ${USRID}~${FILENAME}~${FILESUFX}~${TABSCHEMA}~${TABNAME}~${CHARSET}~${HASHEADER}~${MAXERRNO}~${ISCOMP}~${COMPMTHD}
			String shellR = "sh " + linMon.getShellName() + " " + linMon.getFolderName();
			xxlJobInfo.setGlueSource(shellR);
			xxlJobService.add(xxlJobInfo);
			XxlJobInfo byJobDesc = xxlJobInfoDao.findByJobDesc(xxlJobInfo.getJobDesc());
			logger.info("sjcxlinux监控调用脚本jobid=" + byJobDesc.getId());
			JobTriggerPoolHelper.trigger(byJobDesc.getId(), TriggerTypeEnum.MANUAL, -1, null, executorParam, addressList);
//			xxlJobLog = xxlJobLogDao.findByJobId(byJobDesc.getId());
//			xxlJobService.remove(byJobDesc.getId());
//
//			logger.info("sjcx调用脚本返回logid=" + xxlJobLog.getId());
			return  new ReturnT<String>(Integer.toString(byJobDesc.getId()));
		} catch (NumberFormatException e) {
			logger.error("sjcxlinux监控调用shell报错", e);
			return ReturnT.FAIL;
		}

	}

	@RequestMapping("/nextTriggerTime")
	@ResponseBody
	public ReturnT<List<String>> nextTriggerTime(String scheduleType, String scheduleConf) {

		XxlJobInfo paramXxlJobInfo = new XxlJobInfo();
		paramXxlJobInfo.setScheduleType(scheduleType);
		paramXxlJobInfo.setScheduleConf(scheduleConf);

		List<String> result = new ArrayList<>();
		try {
			Date lastTime = new Date();
			for (int i = 0; i < 5; i++) {
				lastTime = JobScheduleHelper.generateNextValidTime(paramXxlJobInfo, lastTime);
				if (lastTime != null) {
					result.add(DateUtil.formatDateTime(lastTime));
				} else {
					break;
				}
			}
		} catch (Exception e) {
			logger.error(e.getMessage(), e);
			return new ReturnT<List<String>>(ReturnT.FAIL_CODE, (I18nUtil.getString("schedule_type")+I18nUtil.getString("system_unvalid")) + e.getMessage());
		}
		return new ReturnT<List<String>>(result);

	}
	
}
